package jp.android_group.attender.android.ui;

/*
 * Copyright (c) 2009, "Japan Android Group Attender Team"
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

import java.io.IOException;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

import jp.android_group.attender.android.R;
import jp.android_group.attender.android.entity.Event;
import jp.android_group.attender.android.entity.ServerEntry;
import jp.android_group.attender.android.net.IServerInterface;
import jp.android_group.attender.android.net.ServerInterfaceFactory;

import org.apache.http.client.HttpResponseException;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.MenuItem.OnMenuItemClickListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

/**
 * イベントリスト画面
 * 
 * @author Keiji Ariyama <keiji_ariyama@c-lis.co.jp>
 * 
 */
public class EventListActivity extends BaseActivity {
	public static final String LOG_TAG = "EventListActivity";
	public static final boolean DEBUG_FLG = true;

	// 定数：リクエストコード
	public static final int REQUEST_CODE = 0x799c72;

	// 定数：再試行の回数
	public static final int RETRY_NUMBER = 4;
	public static final int RETRY_WAIT_TIME = 2;

	// 認証情報
	private final LinkedList<ServerEntry> mServerEntries = new LinkedList<ServerEntry>();

	// イベントリスト
	private final List<Event> mEventList = new LinkedList<Event>();

	// ダイアログ
	private ProgressDialog mProgressDialog = null;

	// 画面の要素
	private ListView mLvEventList = null;
	private ListAdapter mListAdapter = null;

	/**
	 * 
	 */
	private OnItemClickListener mLvEventListItemClickListener = new OnItemClickListener() {
		@Override
		public void onItemClick(final AdapterView<?> arg0, View arg1,
				int position, long arg3) {

			final Event eventData = (Event) arg0.getItemAtPosition(position);
			if (mModeOffline && eventData.getLastRetrieveDate() < 0)
				return;

			EventListActivity.this.setProgressBarIndeterminateVisibility(true);

			Thread th = new Thread() {
				public void run() {

					ServerEntry serverEntry = ServerEntry.load(eventData
							.getServerId(), mDb);

					Intent intent = new Intent(EventListActivity.this,
							AttendeeListActivity.class);
					intent.putExtra(ServerEntry.class.getName(), serverEntry);
					intent.putExtra(Event.class.getName(), eventData);
					intent.putExtra(EXTRA_MODE_OFFLINE, mModeOffline);

					// HANDLE_START_ACTIVITY
					Bundle data = new Bundle();
					data.putParcelable(Intent.class.getName(), intent);
					Message msg = mHandler.obtainMessage(HANDLE_START_ACTIVITY);
					msg.setData(data);
					mHandler.sendMessage(msg);

				}
			};
			th.setPriority(Thread.MIN_PRIORITY);
			th.start();
		}
	};
	private volatile boolean mCancelFlg = false;

	Runnable mLoadEvent = new Runnable() {
		@Override
		public void run() {

			if (DEBUG_FLG)
				Log.d(LOG_TAG, "mLoadEvent process is start.");

			mHandler.sendEmptyMessage(HANDLE_SHOW_PROGRESS_DIALOG);

			// オフラインモードでなければ、取得処理を実行
			if (mModeOffline != true) {

				List<Event> list = null;
				for (int i = 0; (i < mServerEntries.size() && mCancelFlg == false); i++) {

					mServerEntry = mServerEntries.get(i);
					IServerInterface serverInterface = ServerInterfaceFactory
							.getInterface(mServerEntry);

					// 現在の取得状況
					Message msg = mHandler
							.obtainMessage(HANDLE_CHANGE_PROGRESS_DIALOG);
					Bundle data = new Bundle();
					data.putString("title", mServerEntry.getLoginId());
					data.putString("message", String.valueOf(mServerEntry
							.getBaseUrl()));
					msg.setData(data);
					mHandler.sendMessage(msg);

					for (int ｊ = 0; (ｊ < RETRY_NUMBER && mCancelFlg == false); ｊ++) {

						try {
							list = serverInterface.getEventData();
						} catch (final HttpResponseException e) {
							if (DEBUG_FLG)
								Log.d(LOG_TAG, e.getLocalizedMessage());
							showToastException(e);
							if (e.getStatusCode() == 401) // Authentication
								// Errorであれば、
								break; // 再試行しない

						} catch (final IOException e) {
							if (DEBUG_FLG)
								Log.d(LOG_TAG, e.getLocalizedMessage());
							showToastException(e);
						}

						if (list != null) {

							// イベント情報の保存
							saveEventList(list, mServerEntry);

							break;

						} else if (mCancelFlg == false) {
							synchronized (mEventList) {
								mEventList.clear();
								mHandler.sendEmptyMessage(HANDLE_RELOAD_LIST);
							}
							synchronized (this) {
								try {
									this.wait(RETRY_WAIT_TIME * 1000);
								} catch (final InterruptedException e) {
									showToastException(e);
								}
							}
						}
					}
				}
			} // if(mModeOffline == false) {

			// 保存した情報の再読み込み
			mHandler.sendEmptyMessage(HANDLE_RELOAD_LIST);
			mHandler.sendEmptyMessage(HANDLE_DISMISS_PROGRESS_DIALOG);
		}
	};
	ServerEntry mServerEntry = null;
	// ハンドラ
	Handler mHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case HANDLE_RELOAD_LIST:
				synchronized (mEventList) {
					listReload();
				}
				break;
			case HANDLE_SHOW_PROGRESS_DIALOG:
				mProgressDialog.setMessage(getResources().getText(
						R.string.retrieving_event_data));
				mCancelFlg = false;
				mProgressDialog.show();
				break;
			case HANDLE_DISMISS_PROGRESS_DIALOG:
				if (mProgressDialog.isShowing())
					mProgressDialog.dismiss();
				break;
			case HANDLE_START_ACTIVITY:
				Intent intent = msg.getData().getParcelable(
						Intent.class.getName());
				startActivityForResult(intent,
						AttendeeListActivity.REQUEST_CODE);
				break;
			}
			;
		}
	};

	private static final int HANDLE_START_ACTIVITY = 0x7687923;
	private static final int HANDLE_RELOAD_LIST = 0x093243;
	private static final int HANDLE_SHOW_PROGRESS_DIALOG = 0x0453;
	private static final int HANDLE_CHANGE_PROGRESS_DIALOG = 0x0271243;
	private static final int HANDLE_DISMISS_PROGRESS_DIALOG = 0x7875435;

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
		setProgressBarIndeterminate(true);

		setContentView(R.layout.event_list);

		mLvEventList = ((ListView) findViewById(R.id.event_list_lv_event));
		mLvEventList.setOnItemClickListener(mLvEventListItemClickListener);
		mListAdapter = new ListAdapter(mEventList);
		mLvEventList.setAdapter(mListAdapter);

		mProgressDialog = new ProgressDialog(EventListActivity.this);
		mProgressDialog.setOnDismissListener(new OnDismissListener() {
			@Override
			public void onDismiss(DialogInterface dialog) {
				mCancelFlg = true;
			}
		});

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jp.android_group.attender.android.ui.BaseActivity#onStart()
	 */
	@Override
	public void onStart() {
		super.onStart();

		setProgressBarIndeterminateVisibility(false);

		if (mModeOffline == false) {
			if (checkConnection()) {
				// 初期化処理
				init();
			} else {
				showOfflineAlertDialog();
			}
		} else {
			// 初期化処理
			init();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onActivityResult(int, int,
	 * android.content.Intent)
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {

		switch (requestCode) {

		// 初期のログイン情報の設定
		case ServerSettingActivity.REQUEST_CODE_INIT:
			switch (resultCode) {
			case Activity.RESULT_OK:
				// 初期化処理
				init();
				break;
			}
			break;

		// 通常のログイン情報の設定
		case ServerSettingActivity.REQUEST_CODE_EDIT:
			switch (resultCode) {
			case Activity.RESULT_OK:
				// 初期化処理
				init();
				break;
			}
			;
			break;

		// 通常のログイン情報の設定
		case AttendeeListActivity.REQUEST_CODE:
			switch (resultCode) {
			case AttendeeListActivity.RESULT_LAUNCH_LOGIN_SETTING:
				if (DEBUG_FLG)
					Log.d(LOG_TAG, "onActivityResult");
				startServerSettingActivity(ServerSettingActivity.REQUEST_CODE_EDIT);
				break;
			}
			break;
		}

	}

	/**
	 * 認証情報の設定
	 */
	private void startServerSettingActivity(int request_code) {

		Intent intent = new Intent(this, ServerSettingActivity.class);
		intent.addCategory(Intent.CATEGORY_DEFAULT);
		intent.setAction(Intent.ACTION_EDIT);
		startActivityForResult(intent, request_code);
	}

	/**
	 * 初期化処理
	 */
	private void init() {

		// ＤＢ接続を開く
		openDatabase();

		synchronized (mServerEntries) {
			mServerEntries.clear();
			mServerEntries.addAll(ServerEntry.load(mDb));
		}

		mCancelFlg = false;

		if (mServerEntries.size() == 0) {

			// 認証情報の設定アクティビティを起動
			startServerSettingActivity(ServerSettingActivity.REQUEST_CODE_INIT);
			return;
		}

		// イベント情報の取得
		new Thread(mLoadEvent).start();

		if (DEBUG_FLG)
			Log.d(LOG_TAG, "initialize process is completed.");

	}

	private synchronized void listReload() {
		if (mDb.isOpen()) {
			synchronized (mEventList) {
				mEventList.clear();
				mEventList.addAll(Event.load(mDb));
				mListAdapter.notifyDataSetChanged();
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * jp.android_group.attender.android.ui.BaseActivity#changeModeOffline(boolean
	 * )
	 */
	@Override
	protected void changeModeOffline(boolean mode) {
		if (mode == false) {
			if (checkConnection()) {
				mModeOffline = false;
				setTitle(R.string.app_name);
			} else {
				showOfflineAlertDialog();
				return;
			}
		} else {
			mModeOffline = true;
			setTitle(getText(R.string.app_name) + " - "
					+ getText(R.string.offline));

			// 初期化処理
			init();

		}

		mListAdapter.notifyDataSetChanged();

	}

	/**
	 * イベント情報の保存
	 */
	private void saveEventList(List<Event> list, ServerEntry serverEntry) {
		synchronized (mEventList) {
			synchronized (mDb) {
				if (mDb.isOpen() && mDb.inTransaction() == false) {
					mDb.beginTransaction();
					try {
						for (Event data : list) {
							data.setServerId(mServerEntry.getId());
							Event.save(data, mDb);
						}
						serverEntry.setLastRetrieveDate(Calendar.getInstance()
								.getTimeInMillis());
						ServerEntry.save(serverEntry, mDb);
						mDb.setTransactionSuccessful();
					} finally {
						mDb.endTransaction();
					}
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onPrepareOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {

		menu.findItem(R.id.event_list_menu_reload).setEnabled(!(mModeOffline));

		if (mModeOffline) {
			menu.findItem(R.id.event_list_menu_offline).setTitle(
					R.string.online);
		} else {
			menu.findItem(R.id.event_list_menu_offline).setTitle(
					R.string.offline);
		}

		return super.onPrepareOptionsMenu(menu);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onCreateOptionsMenu(final Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.event_list, menu);

		MenuItem menuItem = null;

		menuItem = menu.findItem(R.id.event_list_menu_reload);
		menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
			@Override
			public boolean onMenuItemClick(MenuItem item) {

				// 初期化処理
				init();

				return true;
			}
		});

		menuItem = menu.findItem(R.id.event_list_menu_offline);
		menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
			@Override
			public boolean onMenuItemClick(MenuItem item) {
				changeModeOffline(!(mModeOffline));
				return true;
			}
		});

		menuItem = menu.findItem(R.id.event_list_menu_setting);
		menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
			@Override
			public boolean onMenuItemClick(MenuItem item) {
				startServerSettingActivity(ServerSettingActivity.REQUEST_CODE_EDIT);
				return true;
			}
		});

		menuItem = menu.findItem(R.id.event_list_menu_about);
		menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
			@Override
			public boolean onMenuItemClick(MenuItem item) {

				// ダイアログの表示
				showAboutDialog();
				return true;
			}
		});

		return super.onCreateOptionsMenu(menu);
	}

	/**
	 * リストアダプタ
	 */
	private class ListAdapter extends BaseAdapter {

		final List<Event> list;

		ListAdapter(List<Event> val) {
			list = val;
		}

		@Override
		public int getCount() {
			if (list == null)
				return 0;
			return list.size();
		}

		@Override
		public Object getItem(int position) {
			if (list == null)
				return null;
			return list.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			ViewHolder holder;
			if (convertView == null) {
				convertView = View.inflate(EventListActivity.this,
						R.layout.event_list_row, null);
				holder = new ViewHolder();
				holder.eventName = (TextView) convertView
						.findViewById(R.id.event_list_row_event_name);
				holder.serverName = (TextView) convertView
						.findViewById(R.id.event_list_row_server_name);
				holder.lastRetrieveDate = (TextView) convertView
						.findViewById(R.id.event_list_row_last_retrieve_date);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}

			Event eventData = (Event) getItem(position);
			holder.eventName.setText(eventData.getName());
			holder.serverName.setText(eventData.getServerLabel());
			if (mModeOffline) {
				holder.lastRetrieveDate.setVisibility(View.VISIBLE);
			} else {
				holder.lastRetrieveDate.setVisibility(View.INVISIBLE);
			}

			if (eventData.getLastRetrieveDate() > 0) {
				holder.lastRetrieveDate.setText(getText(R.string.last_sync)
						+ " " + eventData.getLastRetrieveDateStr());
			} else {
				holder.lastRetrieveDate
						.setText(getText(R.string.not_available));
			}

			return convertView;
		}

	}

	private static class ViewHolder {
		TextView eventName = null;
		TextView serverName = null;
		TextView lastRetrieveDate = null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * jp.android_group.attender.android.ui.BaseActivity#willConfirmWhenClosing
	 * ()
	 */
	@Override
	protected boolean willConfirmWhenClosing() {
		return true;
	}

}
